package com.bls.executor.node.sentence.simpleStmt;

import com.bls.action.BLSAction;
import com.bls.exception.MyException;
import com.bls.executor.environment.threadPool.ThreadPoolGroup;
import com.bls.executor.node.script.SimpleStmt;

import com.bls.executor.parser.V3Parser;
import org.antlr.v4.runtime.tree.TerminalNode;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;

public class ScheduledStmt extends SimpleStmt {

    ThreadPoolGroup pool = null;
    private IntenseStmt intenseStmt;
    private ListenStmt listenStmt;
    private long period;
    private long delay;
    private int type = 1;

    {
        try {
            pool = BLSAction.getBean(ThreadPoolGroup.class);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // (1) 周期
    // 如：每1天8点，张三 在 喇叭 帮区 执行 喇叭 工具的 发声 部件，喇叭id为xx。
    // (2) 延时
    // 如：2小时 之后，张三 在 喇叭 帮区 执行 喇叭 工具的 发声 部件，喇叭id为xx。
    public ScheduledStmt(V3Parser.ScheduleStmtContext ctx, Map<String, Object> scriptEnvironment) throws MyException {
        if (ctx.timeAdverbial().period() != null) {
            int index = 0;
            List<TerminalNode> number = ctx.timeAdverbial().period().Number();

            long year = ctx.timeAdverbial().period().Year() == null ? 0 : Long.parseLong(number.get(index++).getText());
            long month = ctx.timeAdverbial().period().Month() == null ? 0 : Long.parseLong(number.get(index++).getText());
            long day = ctx.timeAdverbial().period().Day() == null ? 0 : Long.parseLong(number.get(index++).getText());
            long hour = ctx.timeAdverbial().period().Hour() == null ? 0 : Long.parseLong(number.get(index++).getText());
            long minute = ctx.timeAdverbial().period().Minute() == null ? 0 : Long.parseLong(number.get(index++).getText());
            long second = ctx.timeAdverbial().period().Second() == null ? 0 : Long.parseLong(number.get(index).getText());

            LocalDateTime now = LocalDateTime.now();
            LocalDateTime plus = now.plusYears(year).plusMonths(month).plusDays(day).plusHours(hour).plusMinutes(minute).plusSeconds(second);
            period = Duration.between(now, plus).toMillis();
            type = 1;

        } else {
            int index = 0;
            List<TerminalNode> number = ctx.timeAdverbial().delay().Number();

            long year = ctx.timeAdverbial().delay().Year() == null ? 0 : Long.parseLong(number.get(index++).getText());
            long month = ctx.timeAdverbial().delay().Month() == null ? 0 : Long.parseLong(number.get(index++).getText());
            long day = ctx.timeAdverbial().delay().Day() == null ? 0 : Long.parseLong(number.get(index++).getText());
            long hour = ctx.timeAdverbial().delay().Hour() == null ? 0 : Long.parseLong(number.get(index++).getText());
            long minute = ctx.timeAdverbial().delay().Minute() == null ? 0 : Long.parseLong(number.get(index++).getText());
            long second = ctx.timeAdverbial().delay().Second() == null ? 0 : Long.parseLong(number.get(index).getText());

            LocalDateTime now = LocalDateTime.now();
            LocalDateTime plus = now.plusYears(year).plusMonths(month).plusDays(day).plusHours(hour).plusMinutes(minute).plusSeconds(second);

            delay = Duration.between(now, plus).toMillis();
            type = 2;
        }
        if (ctx.intenseStmt() == null) {
            listenStmt = new ListenStmt(ctx.listenStmt(), scriptEnvironment);
        } else {
            if(ctx.intenseStmt().runToolStmt() != null){
                if (ctx.intenseStmt().runToolStmt().notifyStmt() == null) {
                    intenseStmt = new RunToolStmt(ctx.intenseStmt().runToolStmt(), scriptEnvironment);
                } else {
                    intenseStmt = new NotifyStmt(ctx.intenseStmt().runToolStmt().notifyStmt(), scriptEnvironment);
                }
            }
        }

    }


    public ScheduledFuture<?> runTask() {
        ScheduledExecutorService scheduleThreadPool = pool.getScheduleThreadPool();
        ScheduledFuture<?> task = null;
        if (type == 1) {
            task = scheduleThreadPool.scheduleAtFixedRate(() -> {
                System.out.println("周期执行定时任务");
                // 执行即时性或监听型剧本
                if (intenseStmt == null) {
                    listenStmt.run("");
                } else {
                    intenseStmt.run("");
                }
            }, 1, period, TimeUnit.MILLISECONDS);
        } else if (type == 2) {
            task = scheduleThreadPool.schedule(() -> {
                System.out.println("延时执行定时任务");
                // 执行即时性或监听型剧本
                if (intenseStmt == null) {
                    listenStmt.run("");
                } else {
                    intenseStmt.run("");
                }
            }, delay, TimeUnit.MILLISECONDS);
        }
        return task;
    }
}
